﻿using System;
using GeoAPI.Geometries;
using NetTopologySuite.Algorithm;
using NetTopologySuite.GeometriesGraph;
using NetTopologySuite.Utilities;

namespace NetTopologySuite.EdgeGraph
{
	public class HalfEdge : IComparable<HalfEdge>
	{
		public static HalfEdge Create(Coordinate p0, Coordinate p1)
		{
			HalfEdge halfEdge = new HalfEdge(p0);
			HalfEdge e = new HalfEdge(p1);
			halfEdge.Init(e);
			return halfEdge;
		}

		public static HalfEdge Init(HalfEdge e0, HalfEdge e1)
		{
			if (e0.Sym != null || e1.Sym != null || e0.Next != null || e1.Next != null)
			{
				throw new ArgumentException("Edges are already initialized");
			}
			e0.Init(e1);
			return e0;
		}

		public HalfEdge(Coordinate orig)
		{
			this._orig = orig;
		}

		protected virtual void Init(HalfEdge e)
		{
			this.Sym = e;
			e.Sym = this;
			this.Next = e;
			e.Next = this;
		}

		public Coordinate Orig
		{
			get
			{
				return this._orig;
			}
		}

		public Coordinate Dest
		{
			get
			{
				return this.Sym.Orig;
			}
		}

		public HalfEdge Sym
		{
			get
			{
				return this._sym;
			}
			private set
			{
				this._sym = value;
			}
		}

		public HalfEdge Next
		{
			get
			{
				return this._next;
			}
			private set
			{
				this._next = value;
			}
		}

		public HalfEdge Prev
		{
			get
			{
				return this.Sym.Next.Sym;
			}
		}

		public HalfEdge ONext
		{
			get
			{
				return this.Sym.Next;
			}
		}

		public HalfEdge Find(Coordinate dest)
		{
			HalfEdge halfEdge = this;
			while (halfEdge != null)
			{
				if (halfEdge.Dest.Equals2D(dest))
				{
					return halfEdge;
				}
				halfEdge = halfEdge.ONext;
				if (halfEdge == this)
				{
					return null;
				}
			}
			return null;
		}

		public bool Equals(Coordinate p0, Coordinate p1)
		{
			return this.Orig.Equals2D(p0) && this.Sym.Orig.Equals(p1);
		}

		public void Insert(HalfEdge e)
		{
			if (this.ONext == this)
			{
				this.InsertAfter(e);
				return;
			}
			int num = this.CompareTo(e);
			HalfEdge halfEdge = this;
			for (;;)
			{
				HalfEdge onext = halfEdge.ONext;
				if (onext.CompareTo(e) != num || onext == this)
				{
					break;
				}
				halfEdge = onext;
				if (halfEdge == this)
				{
					goto Block_3;
				}
			}
			halfEdge.InsertAfter(e);
			return;
			Block_3:
			Assert.ShouldNeverReachHere();
		}

		private void InsertAfter(HalfEdge e)
		{
			Assert.IsEquals(this.Orig, e.Orig);
			HalfEdge onext = this.ONext;
			this.Sym.Next = e;
			e.Sym.Next = onext;
		}

		public int CompareTo(HalfEdge e)
		{
			return this.CompareAngularDirection(e);
		}

		public int CompareAngularDirection(HalfEdge e)
		{
			double deltaX = this.DeltaX;
			double deltaY = this.DeltaY;
			double deltaX2 = e.DeltaX;
			double deltaY2 = e.DeltaY;
			if (deltaX == deltaX2 && deltaY == deltaY2)
			{
				return 0;
			}
			double num = (double)QuadrantOp.Quadrant(deltaX, deltaY);
			double num2 = (double)QuadrantOp.Quadrant(deltaX2, deltaY2);
			if (num > num2)
			{
				return 1;
			}
			if (num < num2)
			{
				return -1;
			}
			return CGAlgorithms.ComputeOrientation(e.Orig, e.Dest, this.Dest);
		}

		public double DeltaX
		{
			get
			{
				return this.Sym.Orig.X - this.Orig.X;
			}
		}

		public double DeltaY
		{
			get
			{
				return this.Sym.Orig.Y - this.Orig.Y;
			}
		}

		public override string ToString()
		{
			return string.Format("HE({0} {1}, {2} {3})", new object[]
			{
				this.Orig.X,
				this.Orig.Y,
				this.Sym.Orig.X,
				this.Sym.Orig.Y
			});
		}

		public int Degree()
		{
			int num = 0;
			HalfEdge halfEdge = this;
			do
			{
				num++;
				halfEdge = halfEdge.ONext;
			}
			while (halfEdge != this);
			return num;
		}

		public HalfEdge PrevNode()
		{
			HalfEdge halfEdge = this;
			while (halfEdge.Degree() == 2)
			{
				halfEdge = halfEdge.Prev;
				if (halfEdge == this)
				{
					return null;
				}
			}
			return halfEdge;
		}

		private readonly Coordinate _orig;

		private HalfEdge _sym;

		private HalfEdge _next;
	}
}
